package pl.edu.mimuw.irs.rcp.controller.editor.resources;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.InputStream;
import java.util.EventObject;

import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.gef.DefaultEditDomain;
import org.eclipse.gef.EditDomain;
import org.eclipse.gef.commands.CommandStack;
import org.eclipse.gef.commands.CommandStackListener;
import org.eclipse.gef.ui.properties.UndoablePropertySheetEntry;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.part.EditorPart;
import org.eclipse.ui.part.FileEditorInput;
import org.eclipse.ui.views.properties.IPropertySheetPage;
import org.eclipse.ui.views.properties.PropertySheetPage;

import pl.edu.mimuw.irs.core.model.design.resource.Resources;
import pl.edu.mimuw.irs.core.model.design.resource.Roles;
import pl.edu.mimuw.irs.rcp.persistence.IPersistence;
import pl.edu.mimuw.irs.rcp.persistence.PersistenceAdapter;
import pl.edu.mimuw.irs.rcp.persistence.PersistenceManager;
import pl.edu.mimuw.irs.rcp.persistence.descriptor.HistoryFilesDescriptor;
import pl.edu.mimuw.irs.rcp.persistence.resource.HistoryLoader;
import pl.edu.mimuw.irs.rcp.util.Logger;
import pl.edu.mimuw.irs.rcp.util.MessageCode;
import pl.edu.mimuw.irs.rcp.util.UITexts;

public class ResourcesEditor extends EditorPart implements PropertyChangeListener {
	
	public static final String ID = "pl.edu.mimuw.irs.editor.resources";
	public static final String COMMAND_ID = "pl.edu.mimuw.irs.command.editresources";

	public static final String RESOURCES_FILE = "resources.res";
	
	// *** Attributes

	private Composite composite;
	private Button btnNewResource;
	private Text txtNewResource;
	private Resources model;
	private Roles rolesMap;
	private HistoryFilesDescriptor history;
	private HistoryLoader historyLoader;
	private ResourcesTreeWrapper treResources;
	private boolean looping;
	public Resources getModel() {
		return model;
	}
	public void setModel(Resources model) {
		this.model = model;
	}
	public Roles getRolesMap() {
		if (rolesMap == null) rolesMap = new Roles();
		return rolesMap;
	}
	public void setRolesMap(Roles rolesMap) {
		this.rolesMap = rolesMap;
	}
	public HistoryLoader getHistoryLoader() {
		if (historyLoader == null && history != null) {
			try {
				historyLoader = new HistoryLoader(history);
			} catch (Exception e) {
			}
		}
		return historyLoader;
	}
	
	private EditDomain editDomain;
	private boolean dirty;
	private PropertySheetPage propertySheetPage;
	private CommandStackListener commandStackListener = new CommandStackListener() {
		public void commandStackChanged(EventObject event) {
			setDirty(getCommandStack().isDirty());
		}
	};
	public EditDomain getEditDomain() {
		if (editDomain == null) editDomain = new DefaultEditDomain(this);
		return editDomain;
	}
	public void setDirty(boolean dirty) {
		if (this.dirty != dirty) {
			this.dirty = dirty;
			firePropertyChange(IEditorPart.PROP_DIRTY);
		}
	}
	@Override
	public boolean isDirty() {
		return dirty;
	}
	protected PropertySheetPage getPropertySheetPage() {
		if (propertySheetPage == null) {
			propertySheetPage = new PropertySheetPage();
			propertySheetPage.setRootEntry(
					new UndoablePropertySheetEntry(getCommandStack()));
		}
		return propertySheetPage;
	}
	public CommandStack getCommandStack() {
		return getEditDomain().getCommandStack();
	}
	protected CommandStackListener getCommandStackListener() {
		return commandStackListener;
	}
	
	// *** Methods

	@Override
	public void doSave(IProgressMonitor monitor) {
		IEditorInput editorInput = getEditorInput();
		
		monitor.beginTask(UITexts.get(MessageCode.RESOURCES_SAVE_PROGRESS), IProgressMonitor.UNKNOWN);
		
		if (editorInput instanceof FileEditorInput) {
			FileEditorInput fileEditorInput = (FileEditorInput) editorInput;
			
			IPersistence<Resources> persistence = PersistenceAdapter.getManager(Resources.class);
			InputStream source;
			try {
				source = persistence.objectAsInputStream(getModel());
				fileEditorInput.getFile().setContents(source, IResource.FORCE, null);
				
				PersistenceManager manager = PersistenceManager.getInstance(editorInput);
				if (manager == null) return;
				manager.clearResources();
			} catch (CoreException e) {
				Logger.handle(MessageCode.RESOURCES_SAVE_FILE_PROBLEM, e);
				return;
			} catch (Exception e) {
				Logger.handle(MessageCode.RESOURCES_SAVE_SERIALIZE_PROBLEM, e);
				return;
			}
		} else {
			Logger.handle(MessageCode.RESOURCES_SAVE_INPUT_PROBLEM, editorInput.getClass(), editorInput.getName());
			return;
		}
		
		monitor.done();

		// update CommandStack
		getCommandStack().markSaveLocation();
	}

	@Override
	public void doSaveAs() {

	}

	@Override
	public void init(IEditorSite site, IEditorInput input)
			throws PartInitException {
		setHistory(input);
		setSite(site);
		setInput(input);
		// TODO : setPartName(input.getName());
		getModel().addPropertyChangeListener(this);
		
		
		getCommandStack().addCommandStackListener(getCommandStackListener());
	}
	
	private void setHistory(IEditorInput input) {
		try {
			PersistenceManager manager = PersistenceManager.getInstance(input);
			if (manager != null) {
				history = manager.getHistoryDescriptor();
				if (history != null) history.addPropertyChangeListener(this);
			}
		} catch (CoreException e) {
		}
	}
	
	@Override
	public void dispose() {
		super.dispose();
		getModel().removePropertyChangeListener(this);
		if (this.history != null) history.removePropertyChangeListener(this);
		
		getCommandStack().removeCommandStackListener(getCommandStackListener());
	}

	@Override
	public boolean isSaveAsAllowed() {
		return true;
	}

	@Override
	public void createPartControl(Composite parent) {
		GridData gridData;
		composite = new Composite(parent, SWT.NULL);
		
	    // create the desired layout for this wizard page
		GridLayout gridLayout = new GridLayout();
		gridLayout.numColumns = 2;
		composite.setLayout(gridLayout);
		
		gridData = new GridData();
		gridData.horizontalAlignment = GridData.BEGINNING;
		
		btnNewResource = new Button(composite, SWT.PUSH);
		btnNewResource.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				addResource();
				super.widgetSelected(e);
			}
		});

		btnNewResource.setText(UITexts.get(MessageCode.RESOURCES_EDITOR_NEW));				
		txtNewResource = new Text(composite, SWT.BORDER);
		gridData = new GridData(GridData.FILL_HORIZONTAL);
		txtNewResource.setLayoutData(gridData);
		
		gridData = new GridData(GridData.FILL_HORIZONTAL | GridData.FILL_VERTICAL);
		gridData.horizontalSpan = 2;
		treResources = new ResourcesTreeWrapper(composite, SWT.BORDER | SWT.MULTI | SWT.V_SCROLL, 
		getModel(), getEditDomain());
		treResources.setLayoutData(gridData);
		
//		GridData gridData;
//		Composite composite =  new Composite(parent, SWT.NULL);
//
//	    // create the desired layout for this wizard page
//		GridLayout gridLayout = new GridLayout();
//		gridLayout.numColumns = 2;
//		composite.setLayout(gridLayout);
//		
//		gridData = new GridData();
//		gridData.horizontalAlignment = GridData.BEGINNING;	
//		
//		gridData = new GridData();
//		lblResources = new Label(composite, SWT.NONE);
//		lblResources.setText(UITexts.get(MessageCode.RESOURCES_EDITOR_CONTENTS));
//		gridData = new GridData(GridData.FILL_HORIZONTAL | GridData.FILL_VERTICAL);
//		treResources = new ResourcesTreeWrapper(composite, SWT.BORDER | SWT.MULTI | SWT.V_SCROLL, 
//				getModel(), getEditDomain());
//		treResources.setLayoutData(gridData);
		
		getSite().setSelectionProvider(treResources.getTreeViewer());
	}
	
	@Override
	protected void setInput(IEditorInput input) {
		super.setInput(input);
		
		Resources resources = loadResources(getEditorInput());
		if (resources == null) return;
		
		model = resources;
		reloadHistory();
	}
	
	private Resources loadResources(IEditorInput input) {
		try {
			PersistenceManager manager = PersistenceManager.getInstance(input);
			if (manager == null) return null;
			return manager.getResources();
		} catch (CoreException e) {
			Logger.handle(MessageCode.RESOURCES_LOAD_DESERIALIZE_PROBLEM, e, input);
			return null;
		} catch (Exception e) {
			Logger.handle(MessageCode.RESOURCES_LOAD_DESERIALIZE_PROBLEM, e, input);
			return null;
		}
	}
	
	private void reloadHistory() {
		try {
			if (getHistoryLoader() != null) getHistoryLoader().loadTo(getModel());
		} catch (Exception e) {
			Logger.handle(MessageCode.HISTORY_LOAD_FILE_PROBLEM, e);
		}
	}
	
	private void refresh() {
		treResources.redrawTree();
	}
	
	private void addResource() {
		String name = txtNewResource.getText();
		if (name == null || name.equals("")) name = UITexts.get(MessageCode.RESOURCES_EDITOR_UNNAMED);
		treResources.addResource(name, true);
	}
	
	@Override
	public void setFocus() {
	}
	
	@Override
	public void propertyChange(PropertyChangeEvent arg0) {
		if (looping) return;
		looping = true;
		if (arg0.getSource() != null && arg0.getSource().equals(history)) {
			getHistoryLoader().reset();
		}
		reloadHistory();
		refresh();
		looping = false;
	}

	@SuppressWarnings("unchecked")
	@Override
	public Object getAdapter(Class adapter) {
		if (adapter == CommandStack.class)
			return getCommandStack();
		else if (adapter == EditDomain.class)
			return getEditDomain();
		else if (adapter == IPropertySheetPage.class)
			return getPropertySheetPage();
		// the super implementation handles the rest
		return super.getAdapter(adapter);
	}
}
